home *** CD-ROM | disk | FTP | other *** search
/ Java Primer Plus / Java Primer Plus (Waite Group Proess)(1996).iso / java_Win / demo / Fractal / CLSFractal.java < prev    next >
Text File  |  1995-10-12  |  8KB  |  358 lines

  1. import java.awt.Graphics;
  2. import java.util.Stack;
  3. import java.util.Vector;
  4.  
  5. /**
  6.  * A (not-yet) Context sensitive L-System Fractal applet class.
  7.  *
  8.  * The rules for the Context L-system are read from the java.applet.Applet's
  9.  * attributes and then the system is iteratively applied for the
  10.  * given number of levels, possibly drawing each generation as it
  11.  * is generated.  Note that the ContextLSystem class does not yet
  12.  * handle the lContext and rContext attributes, although this
  13.  * class is already designed to parse the '[' and ']' characters
  14.  * typically used in Context sensitive L-Systems.
  15.  *
  16.  * @author     Jim Graham
  17.  * @version     1.1f, 27 Mar 1995
  18.  */
  19. public class CLSFractal extends java.applet.Applet implements Runnable {
  20.     ContextLSystem cls;
  21.     int fractLevel = 1;
  22.     int repaintDelay = 50;
  23.     boolean incrementalUpdates;
  24.     float startAngle;
  25.     float rotAngle;
  26.     float Xmin;
  27.     float Xmax;
  28.     float Ymin;
  29.     float Ymax;
  30.     int border;
  31.     boolean normalizescaling;
  32.  
  33.     public void init() {
  34.     String s;
  35.     cls = new ContextLSystem(this);
  36.     s = getParameter("level");
  37.     if (s != null) fractLevel = Integer.parseInt(s);
  38.     s = getParameter("incremental");
  39.     if (s != null) incrementalUpdates = s.equals("true");
  40.     s = getParameter("delay");
  41.     if (s != null) repaintDelay = Integer.parseInt(s);
  42.     s = getParameter("startAngle");
  43.     if (s != null) startAngle = Float.valueOf(s).floatValue();
  44.     s = getParameter("rotAngle");
  45.     if (s != null) rotAngle = Float.valueOf(s).floatValue();
  46.     rotAngle = rotAngle / 360 * 2 * 3.14159265358f;
  47.     s = getParameter("border");
  48.     if (s != null) border = Integer.parseInt(s);
  49.     s = getParameter("normalizescale");
  50.     if (s != null) normalizescaling = s.equals("true");
  51.     }
  52.  
  53.     Thread kicker;
  54.  
  55.     public void run() {
  56.     Thread me = Thread.currentThread();
  57.     boolean needsRepaint = false;
  58.     while (kicker == me && cls.getLevel() < fractLevel) {
  59.         cls.generate();
  60.         if (kicker == me && incrementalUpdates) {
  61.         repaint();
  62.         try {Thread.sleep(repaintDelay);} catch (InterruptedException e){}
  63.         } else {
  64.         needsRepaint = true;
  65.         }
  66.     }
  67.     if (kicker == me) {
  68.         kicker = null;
  69.         if (needsRepaint) {
  70.         repaint();
  71.         }
  72.     }
  73.     }
  74.  
  75.     public void start() {
  76.     kicker = new Thread(this);
  77.     kicker.start();
  78.     }
  79.  
  80.     public void stop() {
  81.     kicker = null;
  82.     }
  83.  
  84.     public boolean mouseUp(java.awt.Event evt, int x, int y) {
  85.     cls = new ContextLSystem(this);
  86.     savedPath = null;
  87.     start();
  88.     return true;
  89.     }
  90.  
  91.     String savedPath;
  92.  
  93.     public void paint(Graphics g) {
  94.     String fractalPath = cls.getPath();
  95.     if (fractalPath == null) {
  96.         super.paint(g);
  97.         return;
  98.     }
  99.     if (savedPath == null || !savedPath.equals(fractalPath)) {
  100.         savedPath = fractalPath;
  101.         render(null, fractalPath);
  102.     }
  103.  
  104.     for (int i = 0; i < border; i++) {
  105.         g.draw3DRect(i, i, size().width - i * 2, size().height - i * 2,false);
  106.     }
  107.     render(g, fractalPath);
  108.     }
  109.  
  110.     void render(Graphics g, String path) {
  111.     Stack turtleStack = new Stack();
  112.     CLSTurtle turtle;
  113.  
  114.     if (g == null) {
  115.         Xmin = 1E20f;
  116.         Ymin = 1E20f;
  117.         Xmax = -1E20f;
  118.         Ymax = -1E20f;
  119.         turtle = new CLSTurtle(startAngle, 0, 0, 0, 0, 1, 1);
  120.     } else {
  121.         float frwidth = Xmax - Xmin;
  122.         if (frwidth == 0)
  123.         frwidth = 1;
  124.         float frheight = Ymax - Ymin;
  125.         if (frheight == 0)
  126.         frheight = 1;
  127.         float xscale = (size().width - border * 2 - 1) / frwidth;
  128.         float yscale = (size().height - border * 2 - 1) / frheight;
  129.         int xoff = border;
  130.         int yoff = border;
  131.         if (normalizescaling) {
  132.         if (xscale < yscale) {
  133.             yoff += ((size().height - border * 2)
  134.                  - ((Ymax - Ymin) * xscale)) / 2;
  135.             yscale = xscale;
  136.         } else if (yscale < xscale) {
  137.             xoff += ((size().width - border * 2)
  138.                  - ((Xmax - Xmin) * yscale)) / 2;
  139.             xscale = yscale;
  140.         }
  141.         }
  142.         turtle = new CLSTurtle(startAngle, 0 - Xmin, 0 - Ymin,
  143.                    xoff, yoff, xscale, yscale);
  144.     }
  145.  
  146.     for (int pos = 0; pos < path.length(); pos++) {
  147.         switch (path.charAt(pos)) {
  148.         case '+':
  149.         turtle.rotate(rotAngle);
  150.         break;
  151.         case '-':
  152.         turtle.rotate(-rotAngle);
  153.         break;
  154.         case '[':
  155.         turtleStack.push(turtle);
  156.         turtle = new CLSTurtle(turtle);
  157.         break;
  158.         case ']':
  159.         turtle = (CLSTurtle) turtleStack.pop();
  160.         break;
  161.         case 'f':
  162.         turtle.jump();
  163.         break;
  164.         case 'F':
  165.         if (g == null) {
  166.             includePt(turtle.X, turtle.Y);
  167.             turtle.jump();
  168.             includePt(turtle.X, turtle.Y);
  169.         } else {
  170.             turtle.draw(g);
  171.         }
  172.         break;
  173.         default:
  174.         break;
  175.         }
  176.     }
  177.     }
  178.  
  179.     void includePt(float x, float y) {
  180.     if (x < Xmin)
  181.         Xmin = x;
  182.     if (x > Xmax)
  183.         Xmax = x;
  184.     if (y < Ymin)
  185.         Ymin = y;
  186.     if (y > Ymax)
  187.         Ymax = y;
  188.     }
  189. }
  190.  
  191. /**
  192.  * A Logo turtle class designed to support Context sensitive L-Systems.
  193.  *
  194.  * This turtle performs a few basic maneuvers needed to support the
  195.  * set of characters used in Context sensitive L-Systems "+-fF[]".
  196.  *
  197.  * @author     Jim Graham
  198.  * @version     1.1f, 27 Mar 1995
  199.  */
  200. class CLSTurtle {
  201.     float angle;
  202.     float X;
  203.     float Y;
  204.     float scaleX;
  205.     float scaleY;
  206.     int xoff;
  207.     int yoff;
  208.  
  209.     public CLSTurtle(float ang, float x, float y,
  210.              int xorg, int yorg, float sx, float sy) {
  211.     angle = ang;
  212.     scaleX = sx;
  213.     scaleY = sy;
  214.     X = x * sx;
  215.     Y = y * sy;
  216.     xoff = xorg;
  217.     yoff = yorg;
  218.     }
  219.  
  220.     public CLSTurtle(CLSTurtle turtle) {
  221.     angle = turtle.angle;
  222.     X = turtle.X;
  223.     Y = turtle.Y;
  224.     scaleX = turtle.scaleX;
  225.     scaleY = turtle.scaleY;
  226.     xoff = turtle.xoff;
  227.     yoff = turtle.yoff;
  228.     }
  229.  
  230.     public void rotate(float theta) {
  231.     angle += theta;
  232.     }
  233.  
  234.     public void jump() {
  235.     X += (float) Math.cos(angle) * scaleX;
  236.     Y += (float) Math.sin(angle) * scaleY;
  237.     }
  238.  
  239.     public void draw(Graphics g) {
  240.     float x = X + (float) Math.cos(angle) * scaleX;
  241.     float y = Y + (float) Math.sin(angle) * scaleY;
  242.     g.drawLine((int) X + xoff, (int) Y + yoff,
  243.            (int) x + xoff, (int) y + yoff);
  244.     X = x;
  245.     Y = y;
  246.     }
  247. }
  248.  
  249. /**
  250.  * A (non-)Context sensitive L-System class.
  251.  *
  252.  * This class initializes the rules for Context sensitive L-Systems
  253.  * (pred, succ, lContext, rContext) from the given java.applet.Applet's attributes.
  254.  * The generate() method, however, does not (yet) apply the lContext
  255.  * and rContext parts of the rules.
  256.  *
  257.  * @author     Jim Graham
  258.  * @version     1.1f, 27 Mar 1995
  259.  */
  260. class ContextLSystem {
  261.     String axiom;
  262.     Vector rules = new Vector();
  263.     int level;
  264.  
  265.     public ContextLSystem(java.applet.Applet app) {
  266.     axiom = app.getParameter("axiom");
  267.     int num = 1;
  268.     while (true) {
  269.         String pred = app.getParameter("pred"+num);
  270.         String succ = app.getParameter("succ"+num);
  271.         if (pred == null || succ == null) {
  272.         break;
  273.         }
  274.         rules.addElement(new CLSRule(pred, succ,
  275.                      app.getParameter("lContext"+num),
  276.                      app.getParameter("rContext"+num)));
  277.         num++;
  278.     }
  279.     currentPath = new StringBuffer(axiom);
  280.     level = 0;
  281.     }
  282.  
  283.     public int getLevel() {
  284.     return level;
  285.     }
  286.  
  287.     StringBuffer currentPath;
  288.  
  289.     public synchronized String getPath() {
  290.     return ((currentPath == null) ? null : currentPath.toString());
  291.     }
  292.  
  293.     private synchronized void setPath(StringBuffer path) {
  294.     currentPath = path;
  295.     level++;
  296.     }
  297.  
  298.     public void generate() {
  299.     StringBuffer newPath = new StringBuffer();
  300.     int pos = 0;
  301.     while (pos < currentPath.length()) {
  302.         CLSRule rule = findRule(pos);
  303.         if (rule == null) {
  304.         newPath.append(currentPath.charAt(pos));
  305.         pos++;
  306.         } else {
  307.         newPath.append(rule.succ);
  308.         pos += rule.pred.length();
  309.         }
  310.     }
  311.     setPath(newPath);
  312.     }
  313.  
  314.     public CLSRule findRule(int pos) {
  315.     for (int i = 0; i < rules.size(); i++) {
  316.         CLSRule rule = (CLSRule) rules.elementAt(i);
  317.         if (rule.matches(currentPath, pos)) {
  318.         return rule;
  319.         }
  320.     }
  321.     return null;
  322.     }
  323. }
  324.  
  325. /**
  326.  * A Context sensitive L-System production rule.
  327.  *
  328.  * This class encapsulates a production rule for a Context sensitive
  329.  * L-System (pred, succ, lContext, rContext).
  330.  * The matches() method, however, does not (yet) verify the lContext
  331.  * and rContext parts of the rule.
  332.  *
  333.  * @author     Jim Graham
  334.  * @version     1.1f, 27 Mar 1995
  335.  */
  336. class CLSRule {
  337.     String pred;
  338.     String succ;
  339.     String lContext;
  340.     String rContext;
  341.  
  342.     public CLSRule(String p, String d, String l, String r) {
  343.     pred = p;
  344.     succ = d;
  345.     lContext = l;
  346.     rContext = r;
  347.     }
  348.  
  349.     public boolean matches(StringBuffer sb, int pos) {
  350.     if (pos + pred.length() > sb.length()) {
  351.         return false;
  352.     }
  353.     char cb[] = new char[pred.length()];
  354.     sb.getChars(pos, pos + pred.length(), cb, 0);
  355.     return pred.equals(new String(cb));
  356.     }
  357. }
  358.